﻿namespace CatClient
{
    using CatClient.Message;
    using CatClient.Message.Spi.Internals;
    using System;
    using System.Threading.Tasks;

    public class CatTask
    {
        private readonly Action _action;
        private readonly string _type;
        private readonly string _name;
        internal const string DefaultCatType = "Forked";
        internal const string DefaultCatName = "CatTask";

        public CatTask(Action action) : this(action, "Forked", "CatTask")
        {
        }

        public CatTask(Action action, string type, string name)
        {
            this._action = action;
            this._type = type;
            this._name = name;
        }

        public static Task PureRun(Action action)
        {
            DefaultMessageManager.CurrentKey key = Cat.GetCurrent();
            Task task1 = new Task(delegate {
                Cat.SetCurrent(key);
                action();
            });
            task1.Start();
            return task1;
        }

        public static Task<TResult> PureRun<TResult>(Func<TResult> func)
        {
            DefaultMessageManager.CurrentKey key = Cat.GetCurrent();
            Task<TResult> task1 = new Task<TResult>(delegate {
                Cat.SetCurrent(key);
                return func();
            });
            task1.Start();
            return task1;
        }

        public Task Run() => 
            Run(this._action, this._type, this._name);

        public static Task Run(Action action) => 
            Run(action, "Forked", "CatTask");

        public static Task<T> Run<T>(Func<T> func) => 
            Run<T>(func, "Forked", "CatTask");

        public static Task Run(Action action, string type, string name)
        {
            IForkedTransaction forkedTran = Cat.NewForkedTransaction(type, name);
            Task task1 = new Task(delegate {
                forkedTran.Fork();
                action();
                forkedTran.Complete();
            });
            task1.Start();
            return task1;
        }

        public static Task<T> Run<T>(Func<T> func, string type, string name)
        {
            IForkedTransaction forkedTran = Cat.NewForkedTransaction(type, name);
            Task<T> task1 = new Task<T>(delegate {
                forkedTran.Fork();
                forkedTran.Complete();
                return func();
            });
            task1.Start();
            return task1;
        }
    }

    public class CatTask<TResult>
    {
        private readonly Func<TResult> _func;
        private readonly string _type;
        private readonly string _name;

        public CatTask(Func<TResult> func) : this(func, "Forked", "CatTask")
        {
        }

        public CatTask(Func<TResult> func, string type, string name)
        {
            this._func = func;
            this._type = type;
            this._name = name;
        }

        public Task<TResult> Run() =>
            CatTask.Run<TResult>(this._func, this._type, this._name);
    }
}

